package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author mqx
 * @date 2020-12-5 15:12:38
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public void testLock() {
        //  上锁
        RLock lock = null;
        try {
            lock = redissonClient.getLock("lock");
            lock.lock();
            String values = redisTemplate.opsForValue().get("num");
            //  false: return
            if (StringUtils.isEmpty(values)){
                return;
            }
            //   true: ++num 再放入缓存
            int num = Integer.parseInt(values);
            redisTemplate.opsForValue().set("num",String.valueOf(++num));

        } catch (NumberFormatException e) {
            e.printStackTrace();
        } finally {
            if (lock!=null) {
                lock.unlock();
            }
        }
    }

    @Override
    public String readLock() {
        //  读写锁的时候，RReadWriteLock 对象使用的是同一把锁
        RReadWriteLock anyRWLock = redissonClient.getReadWriteLock("anyRWLock");

        //  上锁
        RLock rLock = anyRWLock.readLock();
        rLock.lock(10,TimeUnit.SECONDS);

        String msg = redisTemplate.opsForValue().get("msg");
        return msg;
    }

    @Override
    public String writeLock() {
        //  获取锁的对象
        RReadWriteLock anyRWLock = redissonClient.getReadWriteLock("anyRWLock");
        //  上锁
        RLock rLock = anyRWLock.writeLock();
        //  10 秒自动解锁
        rLock.lock(10,TimeUnit.SECONDS);
        //  业务逻辑
        String uuid = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set("msg",uuid);

        return uuid;
    }

//    @Override
//    public void testLock() {
//        //  set key value ex 10 nx;
//        //  执行setnx
//        //  Boolean flag = redisTemplate.opsForValue().setIfAbsent("lock", "ok");
//        //  执行set 命令 包含 setnx,setex
//        //  设置uuid 防止误删锁！
//        String uuid = UUID.randomUUID().toString();
//        Boolean flag = redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS);
//        //  flag= true 上锁成功
//        if (flag){
//            //  获取数据
//            String values = redisTemplate.opsForValue().get("num");
//            //  false: return
//            if (StringUtils.isEmpty(values)){
//                return;
//            }
//            //   true: ++num 再放入缓存
//            int num = Integer.parseInt(values);
//            redisTemplate.opsForValue().set("num",String.valueOf(++num));
//
//            //  执行完成之后。
//            //  String redisUUID = redisTemplate.opsForValue().get("lock");
//            //            if (uuid.equals(redisUUID)){
//            //                //  如何匹配成功，就删除锁
//            //                //  index1 判断完成之后，准备执行删除！ 但是此时cpu 抢占资源给了index2. 给redis 的lock 赋值 v2 .
//            //                //  此时cpu 又将执行权限给了index1
//            //                redisTemplate.delete("lock");
//            //            }
//
//            //  使用lua 脚本删除
//            //  定义lua 脚本
//            String script="if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
//
//            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
//            //  赋值lua 脚本
//            redisScript.setScriptText(script);
//            redisScript.setResultType(Long.class);
//            //  删除
//            redisTemplate.execute(redisScript, Arrays.asList("lock"),uuid);
//
//        }else {
//            //  获取锁失败，等待。
//            try {
//                Thread.sleep(500);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            //  自旋
//            testLock();
//        }
//    }



//    @Override
//    public synchronized void testLock() {
//        /*
//        获取缓存存储的数据	String  set num 0;
//            true:
//                ++num 再放入缓存
//            false:
//                return;
//         */
//        //  String 数据类型 放入数据的方法。redisTemplate.opsForValue() 了解：Jedis  jedis.set(key,value);
//        String values = redisTemplate.opsForValue().get("num");
//        //  false: return
//        if (StringUtils.isEmpty(values)){
//            return;
//        }
//        //   true: ++num 再放入缓存
//        int num = Integer.parseInt(values);
//        redisTemplate.opsForValue().set("num",String.valueOf(++num));
//
//    }
}
